package lzg.blog.config;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CodeGenerator {
    public static void main(String[] args) {
        try {
            // 加载XML配置文件
            File xmlFile = new File("./blog-config/src/main/java/lzg/blog/config/sql/blogSql.xml"); // 假设XML文件名为config.xml
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(xmlFile);
            doc.getDocumentElement().normalize();

            // 获取配置路径
            Element settingAddr = (Element) doc.getElementsByTagName("SettingAddr").item(0);
            String sqlSrc = settingAddr.getAttribute("sqlSrc");
            String enumSrc = settingAddr.getAttribute("enumSrc");
            String beanSrc = settingAddr.getAttribute("beanSrc");
            String dataSrc = settingAddr.getAttribute("dataSrc");

            // 生成枚举类
            generateEnums(doc, enumSrc);
            System.out.println("枚举地址：" + enumSrc);

            // 生成SQL表
            generateSqlTables(doc, sqlSrc);
            System.out.println("SQL表地址：" + sqlSrc);

            // 生成实体类和VO
            generateBeansAndVOs(doc, beanSrc, dataSrc);
            System.out.println("beanSrc：" + beanSrc);
            System.out.println("dataSrc：" + dataSrc);

            System.out.println("代码生成完成！");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 生成枚举类
    private static void generateEnums(Document doc, String enumSrc) throws IOException {
        NodeList enumsList = doc.getElementsByTagName("enum");

        for (int i = 0; i < enumsList.getLength(); i++) {
            Node enumNode = enumsList.item(i);
            if (enumNode.getNodeType() == Node.ELEMENT_NODE) {
                Element enumElement = (Element) enumNode;
                String enumName = enumElement.getAttribute("name");
                String enumDesc = enumElement.getAttribute("desc");

                // 创建枚举类内容
                StringBuilder enumContent = new StringBuilder();
                enumContent.append("package lzg.blog.common.enums;\n\n");
                enumContent.append("/**\n");
                enumContent.append(" * ").append(enumDesc).append("\n");
                enumContent.append(" */\n");
                enumContent.append("enum ").append(enumName.substring(0, 1).toUpperCase())
                        .append(enumName.substring(1)).append(" {\n");

                NodeList describeList = enumElement.getElementsByTagName("describe");
                for (int j = 0; j < describeList.getLength(); j++) {
                    Element describeElement = (Element) describeList.item(j);
                    String name = describeElement.getAttribute("name");
                    String value = describeElement.getAttribute("value");
                    String desc = describeElement.getAttribute("desc");

                    enumContent.append("    ").append(name).append("(").append(value)
                            .append(", \"").append(desc).append("\"),\n");
                }
                // 移除最后一个逗号
                if (describeList.getLength() > 0) {
                    enumContent.setLength(enumContent.length() - 2);
                    enumContent.append("\n");
                }

                enumContent.append(";");
                enumContent.append("\n");
                enumContent.append("    private final int value;\n");
                enumContent.append("    private final String desc;\n\n");
                enumContent.append("    private ").append(enumName.substring(0, 1).toUpperCase())
                        .append(enumName.substring(1)).append("(int value, String desc) {\n");
                enumContent.append("        this.value = value;\n");
                enumContent.append("        this.desc = desc;\n");
                enumContent.append("    }\n\n");
                enumContent.append("    public int getValue() {\n");
                enumContent.append("        return value;\n");
                enumContent.append("    }\n\n");
                enumContent.append("    public String getDesc() {\n");
                enumContent.append("        return desc;\n");
                enumContent.append("    }\n");
                enumContent.append("}\n");

                // 创建目录
                File dir = new File(enumSrc);
                if (!dir.exists()) {
                    dir.mkdirs();
                }

                // 写入文件
                String fileName = enumName.substring(0, 1).toUpperCase() + enumName.substring(1) + ".java";
                FileWriter writer = new FileWriter(new File(enumSrc, fileName));
                writer.write(enumContent.toString());
                writer.close();
            }
        }
    }

    // 生成SQL表
    private static void generateSqlTables(Document doc, String sqlSrc) throws IOException {
        // 获取默认列
        List<Column> defaultColumns = new ArrayList<>();
        Element columnsElement = (Element) doc.getElementsByTagName("Columns").item(0);
        NodeList defaultColumnList = columnsElement.getElementsByTagName("column");
        for (int i = 0; i < defaultColumnList.getLength(); i++) {
            Element columnElement = (Element) defaultColumnList.item(i);
            Column column = new Column(
                    columnElement.getAttribute("name"),
                    columnElement.getAttribute("dataType"),
                    columnElement.getAttribute("length"),
                    columnElement.getAttribute("desc")
            );
            defaultColumns.add(column);
        }

        // 生成表SQL
        NodeList tablesList = doc.getElementsByTagName("table");
        StringBuilder sqlContent = new StringBuilder();

        for (int i = 0; i < tablesList.getLength(); i++) {
            Node tableNode = tablesList.item(i);
            if (tableNode.getNodeType() == Node.ELEMENT_NODE) {
                Element tableElement = (Element) tableNode;
                String tableName = tableElement.getAttribute("name");
                String tableDesc = tableElement.getAttribute("desc");
                boolean addDefColumn = "true".equals(tableElement.getAttribute("isAddDefColumn"));

                sqlContent.append("-- ").append(tableDesc).append("\n");
                sqlContent.append("CREATE TABLE `").append(tableName).append("` (\n");

                // 表特定列
                NodeList columnList = tableElement.getElementsByTagName("column");
                for (int j = 0; j < columnList.getLength(); j++) {
                    Element columnElement = (Element) columnList.item(j);
                    String name = columnElement.getAttribute("name");
                    String dataType = columnElement.getAttribute("dataType");
                    String length = columnElement.getAttribute("length");
                    String desc = columnElement.getAttribute("desc");

                    sqlContent.append("  `").append(name).append("` ");
                    sqlContent.append(dataType);
                    if (!length.isEmpty()) {
                        sqlContent.append("(").append(length).append(")");
                    }
                    sqlContent.append(" COMMENT '").append(desc).append("',\n");
                }

                // 添加默认列
                if (addDefColumn) {
                    for (Column col : defaultColumns) {
                        sqlContent.append("  `").append(col.name).append("` ");
                        sqlContent.append(col.dataType);
                        if (!col.length.isEmpty()) {
                            sqlContent.append("(").append(col.length).append(")");
                        }
                        sqlContent.append(" COMMENT '").append(col.desc).append("',\n");
                    }
                }

                // 移除最后一个逗号
                if (sqlContent.length() > 0) {
                    sqlContent.setLength(sqlContent.length() - 2);
                    sqlContent.append("\n");
                }

                sqlContent.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='").append(tableDesc).append("';\n\n");
            }
        }

        // 创建目录
        File sqlFile = new File(sqlSrc);
        if (!sqlFile.getParentFile().exists()) {
            sqlFile.getParentFile().mkdirs();
        }

        // 写入SQL文件
        FileWriter writer = new FileWriter(sqlFile);
        writer.write(sqlContent.toString());
        writer.close();
    }

    // 生成实体类和VO
    private static void generateBeansAndVOs(Document doc, String beanSrc, String dataSrc) throws IOException {
        // 获取默认列
        List<Column> defaultColumns = new ArrayList<>();
        Element columnsElement = (Element) doc.getElementsByTagName("Columns").item(0);
        NodeList defaultColumnList = columnsElement.getElementsByTagName("column");
        for (int i = 0; i < defaultColumnList.getLength(); i++) {
            Element columnElement = (Element) defaultColumnList.item(i);
            Column column = new Column(
                    columnElement.getAttribute("name"),
                    columnElement.getAttribute("dataType"),
                    columnElement.getAttribute("length"),
                    columnElement.getAttribute("desc")
            );
            defaultColumns.add(column);
        }

        // 处理每个表
        NodeList tablesList = doc.getElementsByTagName("table");
        for (int i = 0; i < tablesList.getLength(); i++) {
            Node tableNode = tablesList.item(i);
            if (tableNode.getNodeType() == Node.ELEMENT_NODE) {
                Element tableElement = (Element) tableNode;
                String tableName = tableElement.getAttribute("name");
                String tableDesc = tableElement.getAttribute("desc");
                boolean addDefColumn = "true".equals(tableElement.getAttribute("isAddDefColumn"));

                // 收集所有列（表特定列 + 默认列）
                List<Column> allColumns = new ArrayList<>();

                // 表特定列
                NodeList columnList = tableElement.getElementsByTagName("column");
                for (int j = 0; j < columnList.getLength(); j++) {
                    Element columnElement = (Element) columnList.item(j);
                    Column column = new Column(
                            columnElement.getAttribute("name"),
                            columnElement.getAttribute("dataType"),
                            columnElement.getAttribute("length"),
                            columnElement.getAttribute("desc")
                    );
                    allColumns.add(column);
                }

                // 添加默认列
                if (addDefColumn) {
                    allColumns.addAll(defaultColumns);
                }

                // 生成实体类
                generateEntityClass(tableName, tableDesc, allColumns, beanSrc + "bean/");

                // 生成VO类
                generateVOClass(tableName, tableDesc, allColumns, beanSrc + "bean/");

                // 生成Mapper接口
                generateMapperInterface(tableName, dataSrc + "mapper/");
            }
        }
    }

    // 生成实体类
    private static void generateEntityClass(String tableName, String tableDesc, List<Column> columns, String outputDir) throws IOException {
        String className = camelCase(tableName) + "Bean";

        StringBuilder content = new StringBuilder();
        content.append("package lzg.blog.common.bean;\n\n");
        content.append("import com.baomidou.mybatisplus.annotation.TableName;\n");
        content.append("import java.io.Serializable;\n");
        content.append("import java.util.Date;\n\n");
        content.append("/**\n");
        content.append(" * ").append(tableDesc).append("\n");
        content.append(" */\n");
        content.append("@TableName(\"").append(tableName).append("\")\n");
        content.append("public class ").append(className).append(" implements Serializable {\n");
        content.append("    private static final long serialVersionUID = 1L;\n\n");

        // 生成字段
        for (Column column : columns) {
            content.append("    /**\n");
            content.append("     * ").append(column.desc).append("\n");
            content.append("     */\n");
            content.append("    private ").append(getJavaType(column.dataType)).append(" ").append(column.name).append(";\n\n");
        }

        // 生成getter和setter
        for (Column column : columns) {
            String fieldName = column.name;
            String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

            content.append("    public ").append(getJavaType(column.dataType)).append(" get").append(methodName).append("() {\n");
            content.append("        return ").append(fieldName).append(";\n");
            content.append("    }\n\n");

            content.append("    public void set").append(methodName).append("(").append(getJavaType(column.dataType)).append(" ").append(fieldName).append(") {\n");
            content.append("        this.").append(fieldName).append(" = ").append(fieldName).append(";\n");
            content.append("    }\n\n");
        }

        content.append("}");

        // 写入文件
        writeJavaFile(outputDir, className, content.toString());
    }

    // 生成VO类
    private static void generateVOClass(String tableName, String tableDesc, List<Column> columns, String outputDir) throws IOException {
        String className = camelCase(tableName) + "VO";

        StringBuilder content = new StringBuilder();
        content.append("package lzg.blog.common.vo;\n\n");
        content.append("import java.io.Serializable;\n");
        content.append("import java.util.Date;\n\n");
        content.append("/**\n");
        content.append(" * ").append(tableDesc).append("VO\n");
        content.append(" */\n");
        content.append("public class ").append(className).append(" implements Serializable {\n");
        content.append("    private static final long serialVersionUID = 1L;\n\n");

        // 生成字段
        for (Column column : columns) {
            content.append("    /**\n");
            content.append("     * ").append(column.desc).append("\n");
            content.append("     */\n");
            content.append("    private ").append(getJavaType(column.dataType)).append(" ").append(column.name).append(";\n\n");
        }

        // 生成getter和setter
        for (Column column : columns) {
            String fieldName = column.name;
            String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

            content.append("    public ").append(getJavaType(column.dataType)).append(" get").append(methodName).append("() {\n");
            content.append("        return ").append(fieldName).append(";\n");
            content.append("    }\n\n");

            content.append("    public void set").append(methodName).append("(").append(getJavaType(column.dataType)).append(" ").append(fieldName).append(") {\n");
            content.append("        this.").append(fieldName).append(" = ").append(fieldName).append(";\n");
            content.append("    }\n\n");
        }

        content.append("}");

        // 写入文件
        writeJavaFile(outputDir, className, content.toString());
    }

    // 生成Mapper接口
    private static void generateMapperInterface(String tableName, String outputDir) throws IOException {
        String className = camelCase(tableName) + "Mapper";
        String beanClassName = camelCase(tableName) + "Bean";

        StringBuilder content = new StringBuilder();
        content.append("package lzg.blog.data.mapper;\n\n");
        content.append("import com.baomidou.mybatisplus.core.mapper.BaseMapper;\n");
        content.append("import lzg.blog.common.bean.").append(beanClassName).append(";\n\n");
        content.append("/**\n");
        content.append(" * ").append(tableName).append("Mapper接口\n");
        content.append(" */\n");
        content.append("public interface ").append(className).append(" extends BaseMapper<").append(beanClassName).append("> {\n\n");
        content.append("}");

        // 写入文件
        writeJavaFile(outputDir, className, content.toString());
    }

    // 辅助方法：将表名转换为驼峰命名
    private static String camelCase(String tableName) {
        // 简单处理，假设表名是中文，直接转换为拼音首字母大写
        // 实际应用中可能需要更复杂的转换逻辑
        return tableName.substring(0, 1).toUpperCase() + tableName.substring(1);
    }

    // 辅助方法：将SQL类型转换为Java类型
    private static String getJavaType(String sqlType) {
        switch (sqlType.toLowerCase()) {
            case "varchar":
            case "char":
                return "String";
            case "int":
                return "Integer";
            case "bigint":
                return "Long";
            case "date":
            case "datetime":
                return "Date";
            case "decimal":
                return "BigDecimal";
            case "double":
                return "Double";
            case "float":
                return "Float";
            case "boolean":
                return "Boolean";
            default:
                return "String";
        }
    }

    // 辅助方法：写入Java文件
    private static void writeJavaFile(String outputDir, String className, String content) throws IOException {
        File dir = new File(outputDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        FileWriter writer = new FileWriter(new File(dir, className + ".java"));
        writer.write(content);
        writer.close();
    }

    // 内部类：表示列信息
    static class Column {
        String name;
        String dataType;
        String length;
        String desc;

        Column(String name, String dataType, String length, String desc) {
            this.name = name;
            this.dataType = dataType;
            this.length = length;
            this.desc = desc;
        }
    }
}
